package com.xianan.xuhui.netsecurityproject.utils;


/**
 * @Author laobuzhang
 * @Description: jwt工具类，通过UUID算法生成JWT的id，通过subject参数将要储存的信息放在jwt的sub字段中
 */



import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.UUID;

/**
 * JWT工具类
 */
@Component
public class JwtUtil {

    @Autowired
    private RedisTemplate redisTemplate;

    //有效期为
    public static final Long JWT_TTL = 60 * 60 * 24 * 1000L;//  一天
    //设置秘钥明文
    public static final String JWT_KEY = "BuXiWanGongZuoShi";

    public static String getUUID() {
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        return token;
    }

    /**
     * 生成jtw
     *
     * @param subject token中要存放的数据（json格式）
     * @return
     */
    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
        return builder.compact();
    }

    /**
     * 创建token
     *
     * @param id
     * @param subject
     * @param ttlMillis
     * @return
     */
    public static String createJWT(String id, String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间
        return builder.compact();
    }

    /**
     * 生成jtw
     *
     * @param subject   token中要存放的数据（json格式）
     * @param ttlMillis token超时时间
     * @return
     */
    public static String createJWT(String subject, Long ttlMillis) {
        JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());
        System.out.println("xxx:" + builder.toString());// 设置过期时间
        return builder.compact();
    }

    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        // jwt签名加密算法HS256
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        // 密钥
        SecretKey secretKey = generalKey();
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if (ttlMillis == null) {
            ttlMillis = JwtUtil.JWT_TTL;
        }
        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        return Jwts.builder()
                .setId(uuid)           // 唯一的ID，通过这个ID可以在redis中找到该JWT对应的用户信息
                .setSubject(subject)   // 主题  可以是JSON数据
                .setIssuer("sg")       // 签发者
                .setIssuedAt(now)      // 签发时间
                .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
                .setExpiration(expDate);
    }


    /**
     * 生成加密后的秘钥 secretKey
     *
     * @return
     */
    public static SecretKey generalKey() {
        byte[] keyBytes = JWT_KEY.getBytes(StandardCharsets.UTF_8);
        // 使用HmacSHA256算法生成密钥（HS256对应HmacSHA256）
        return new SecretKeySpec(keyBytes, "HmacSHA256");
    }

    /**
     * 解析jwt，最主要目的拿到jwt的id
     *
     * @param jwt
     * @return
     * @throws Exception
     */
    public  Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        System.out.println("secretKey:" + secretKey.toString());
        Claims claims = Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt)
                .getBody();
        String jti = claims.getId();
        String userId = claims.getSubject();
        String blacklistKey = "refresh_blacklist:" + userId;
        // 检查 jti 是否在黑名单列表
        List<String> blacklistedJtis = redisTemplate.opsForList().range(blacklistKey, 0, -1);
        System.out.println("传过来的Token：" + jwt);
        for(String blacklistedJti : blacklistedJtis){
            System.out.println("asdada:" + blacklistedJti);
        }
        if (blacklistedJtis != null && blacklistedJtis.contains(jti)) {
            System.out.println("Token 已被撤销");
            throw new RuntimeException("Token 已被撤销");
        }

        return claims;

    }


}

